#include <session.h>
#include <sysutil.h>
#include <regular_expression.h>
#include <ftpcode.h>
#include <ftpproto.h>
#include <tunable.h>
#include <privsock.h>

int list_command(session_t *sess,int detail);
int get_transfer_fd(session_t *sess);
void upload_common(session_t *sess,int isappe);
void limit_rate(session_t *sess,int bytes_transfered,int is_upload);
void start_cmdio_alarm(void);
void start_data_alarm(void);

static void do_user(session_t *sess);
static void do_pass(session_t *sess);
static void do_cwd(session_t *sess);
static void do_cdup(session_t *sess);
static void do_quit(session_t *sess);
static void do_port(session_t *sess);
static void do_pasv(session_t *sess);
static void do_type(session_t *sess);
static void do_stru(session_t *sess);
static void do_mode(session_t *sess);
static void do_retr(session_t *sess);
static void do_stor(session_t *sess);
static void do_appe(session_t *sess);
static void do_list(session_t *sess);
static void do_nlst(session_t *sess);
static void do_rest(session_t *sess);
static void do_abor(session_t *sess);
static void do_pwd(session_t *sess);
static void do_mkd(session_t *sess);
static void do_rmd(session_t *sess);
static void do_dele(session_t *sess);
static void do_rnfr(session_t *sess);
static void do_rnto(session_t *sess);
static void do_site(session_t *sess);
static void do_syst(session_t *sess);
static void do_feat(session_t *sess);
static void do_size(session_t *sess);
static void do_stat(session_t *sess);
static void do_noop(session_t *sess);
static void do_help(session_t *sess);
static void do_opts(session_t *sess);
static void do_mdtm(session_t *sess);
static void do_cmdnotimpl(session_t *sess);
static void do_badcmd(session_t *sess);


typedef struct ftpcmd
{
	const char *cmd;
	void (*cmd_handler)(session_t *sess);
} ftpcmd_t;

static ftpcmd_t ctrl_cmds[] = {
	/* 访问控制命令 */
	{"USER",	do_user	},
	{"PASS",	do_pass	},
	{"CWD",		do_cwd	},
	{"XCWD",	do_cwd	},
	{"CDUP",	do_cdup	},
	{"XCUP",	do_cdup	},
	{"QUIT",	do_quit	},
	{"ACCT",	NULL	},
	{"SMNT",	NULL	},
	{"REIN",	NULL	},
	/* 传输参数命令 */
	{"PORT",	do_port	},
	{"PASV",	do_pasv	},
	{"TYPE",	do_type	},
	{"STRU",	do_stru	},
	{"MODE",	do_mode	},

	/* 服务命令 */
	{"RETR",	do_retr	},
	{"STOR",	do_stor	},
	{"APPE",	do_appe	},
	{"LIST",	do_list	},
	{"NLST",	do_nlst	},
	{"REST",	do_rest	},
	{"ABOR",	do_abor	},
	{"\377\364\377\362ABOR", do_abor},
	{"PWD",		do_pwd	},
	{"XPWD",	do_pwd	},
	{"MKD",		do_mkd	},
	{"XMKD",	do_mkd	},
	{"RMD",		do_rmd	},
	{"XRMD",	do_rmd	},
	{"DELE",	do_dele	},
	{"RNFR",	do_rnfr	},
	{"RNTO",	do_rnto	},
	{"SITE",	do_site	},
	{"SYST",	do_syst	},
	{"FEAT",	do_feat },
	{"SIZE",	do_size	},
	{"STAT",	do_stat	},
	{"NOOP",	do_noop	},
	{"HELP",	do_help	},
	{"STOU",	NULL	},
	{"ALLO",	NULL	},
	{"OPTS",	do_opts	},
	{"MDTM",	do_mdtm },
	{NULL,		NULL	}
};

session_t *psess = NULL;
void handle_ctrl_alarm_timeout(int sig)
{
	//DEBUG_PRINT("in %s\n",__func__);
	if(!psess->data_process) {
		shutdown(psess->ctrl_fd,SHUT_RD);
		const char *presponse_str = \
			FTP_RESPONSE_STR(FTP_IDLE_TIMEOUT,"Timeout.");
		writen(psess->ctrl_fd,presponse_str,strlen(presponse_str));
		shutdown(psess->ctrl_fd,SHUT_WR);
		exit(EXIT_FAILURE);
	} else {
		//处于数据传输的状态收到了超时信号
		psess->data_process = 0;
		start_data_alarm();
	}
}

void start_cmdio_alarm(void)
{
	//DEBUG_PRINT("in %s\n",__func__);
	if(tunable_idle_session_timeout > 0) {
		//安装信号
		signal(SIGALRM,handle_ctrl_alarm_timeout);
		alarm(tunable_idle_session_timeout);
	}
}

void handler_data_alarm_timeout(int sig)
{
	//DEBUG_PRINT("in %s\n",__func__);
	if(!psess->data_process) {
		const char *presponse_str = \
			FTP_RESPONSE_STR(FTP_IDLE_TIMEOUT,
				"Data timeout Reconnect.sorry.");
		writen(psess->ctrl_fd,presponse_str,strlen(presponse_str));
		close(psess->data_fd);
		exit(EXIT_FAILURE);
	}
	//处于数据传输的状态收到了超时信号
	psess->data_process = 0;
	start_data_alarm();
}

typedef void (*sighandler_t)(int);

void start_data_alarm(void)
{
	//DEBUG_PRINT("in %s \n",__func__);
	if(tunable_data_connection_timeout > 0) {
		//安装信号
		signal(SIGALRM,handler_data_alarm_timeout);
		alarm(tunable_data_connection_timeout);
	} else if(tunable_idle_session_timeout > 0) {
		//关闭先前关闭的闹钟
		alarm(0);
	}
}

void
ftp_proto_process(session_t *sess)
{
	psess = sess;
	//首先发送220信息给客户端
	const char *s = FTP_RESPONSE_STR(FTP_GREET,"(miniftpd 0.1)");
	writen(sess->ctrl_fd,s,strlen(s));
	//从客户端接收数据
	int ret;
	while(1) {
		memset(sess->cmdline,0,sizeof(sess->cmdline));
		memset(sess->cmd,0,sizeof(sess->cmd));
		memset(sess->arg,0,sizeof(sess->arg));
		//空闲断开
		start_cmdio_alarm();
		ret = readline(sess->ctrl_fd,sess->cmdline,MAX_COMMAND_LINE);
		//得到了一行就开始进行FTP命令解析
		if(ret < 0) {
			//注意还要关闭nobody进程
			//服务进程和nobody进程采用内部命令的方式进行交流
			ERR_EXIT("readline");
		} else if(0 == ret) {
			exit(EXIT_SUCCESS);
		}
		//DEBUG_PRINT("cmdline=[%s]\n",sess->cmdline);
		//去除/r/n
		//在原项目中是是封装了几个函数，这里采用pcre封装的库进行处理
		regular_expression(sess->cmdline,"s/\r\n//");
		DEBUG_PRINT("cmdline=[%s]\n",sess->cmdline);
		//还有一个字符串分割的函数，可以使用自己以前写的一个字符串分割函数
		str_split(sess->cmdline,sess->cmd,sess->arg,' ');
		DEBUG_PRINT("cmd=[%s] arg=[%s]\n",sess->cmd,sess->arg);
		//将字符串转换为大写
		str_upper(sess->cmd);
		//进行正式的命令解析
		int i = 0;
		int size = sizeof(ctrl_cmds) / sizeof(ctrl_cmds[0]);
		for(i = 0;i < size;++i) {
			if(strcmp(ctrl_cmds[i].cmd,sess->cmd) == 0) {
				if(NULL != ctrl_cmds[i].cmd_handler) {
					ctrl_cmds[i].cmd_handler(sess);
					break;
				} else {
					//如果命令处理不支持，可以响应给客户端502
					do_cmdnotimpl(sess);
					break;
				}
			}
		}
		if(i == size) {
			//说明是错误的命令需要进行响应
			do_badcmd(sess);
		}
	}
}

static void
do_user(session_t *sess)
{
	//USER命令的响应实现
	//这个时候USER后面跟随的是用户名具体名称需要根据它来获取密码
	const char *presponse_str = NULL;
	struct passwd *pw = getpwnam(sess->arg);
	if(NULL == pw) {
		//说明用户不存在
		//presponse_str = "530 Login incorrect.\r\n";
		presponse_str = FTP_RESPONSE_STR(FTP_LOGINERR,"Login incorrect.");
	} else {
		//说明用户有密码存在，但是还需要进一步验证
		//presponse_str = "331 Please specify the password.\r\n";
		sess->uid = pw->pw_uid;
		presponse_str = FTP_RESPONSE_STR(FTP_GIVEPWORD,"Please specify the password.");
	}
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}

void handle_sigurg(int sig)
{
	//收到了一个紧急数据
	//如果没有处于接收数据的状态就直接返回
	if(psess->data_fd < -1) {
		return;
	}
	char cmdline[MAX_COMMAND_LINE] = {0};
	int ret = readline(psess->ctrl_fd,
		cmdline,MAX_COMMAND_LINE);
	if(ret <= 0) {
		ERR_EXIT("readline");
	}
	if(regular_expression(cmdline,"m/ABOR/")) {
		psess->abor_received = 1;
		shutdown(psess->data_fd,SHUT_RDWR);
	} else {
		const char *presponse_str = \
			FTP_RESPONSE_STR(FTP_BADCMD,"Unknown command.");
		writen(psess->ctrl_fd,presponse_str,strlen(presponse_str));
	}
}

static void
do_pass(session_t *sess)
{
	//这里需要注意前面session的代码中对于nobody进程的设置，要注意设置代码的
	//位置不能影响到这里的子进程只能是创建子进程后将父进程改为nobody进程
	//PASS命令的响应实现
	const char *presponse_str = NULL;
	//PASS命令将密码传递了过来
	//这里要对之前得到的密码情况进行验证
	struct passwd *pw = getpwuid(sess->uid);
	if(NULL == pw) {
		//用户不存在
		DEBUG_PRINT("no user\n");
		presponse_str = FTP_RESPONSE_STR(FTP_LOGINERR,"Login incorrect.");
		writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
		return;
	} else {
		struct spwd *sp = getspnam(pw->pw_name);
		//说明用户名密码没有
		if(NULL == sp) {
			DEBUG_PRINT("no pwd\n");
			presponse_str = FTP_RESPONSE_STR(FTP_LOGINERR,"Login incorrect.");
			writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
			return;
		} else {
			//有密码需要进行进一步的比较
			//linux中存放的密码文件是已经加密过的
			//ftp传递过来的是明文，需要进行进一步的转换
			char *encrypted_pass = crypt(sess->arg,sp->sp_pwdp);
			if(0 == strcmp(encrypted_pass,sp->sp_pwdp)) {
				presponse_str = FTP_RESPONSE_STR(FTP_LOGINOK,"Login successful.");
			} else {
				DEBUG_PRINT("pwd error\n");
				presponse_str = FTP_RESPONSE_STR(FTP_LOGINERR,"Login incorrect.");
				writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
				return;
			}
		}
	}
	//每登陆成功一个用户就需要进行带外数据的信号的注册
	signal(SIGURG,handle_sigurg);
	activate_sigurg(sess->ctrl_fd);
	//登陆的时候要对umask进行更改
	umask(tunable_local_umask);
	//这里应该是用户实际登陆的进程，后面需要进行修改
	setegid(pw->pw_gid);
	seteuid(pw->pw_uid);
	chdir(pw->pw_dir);
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}

void
do_cmdnotimpl(session_t *sess)
{
	const char *presponse_str = \
		FTP_RESPONSE_STR(FTP_COMMANDNOTIMPL,"Unimplement command.");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}

void do_badcmd(session_t *sess)
{
	const char *presponse_str = \
		FTP_RESPONSE_STR(FTP_BADCMD,"Unknown command.");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}

void do_cwd(session_t *sess)
{
	//CWD改变路径
	int ret = chdir(sess->arg);
	const char *presponse_str = NULL;
	if(ret < 0) {
		presponse_str = FTP_RESPONSE_STR(FTP_FILEFAIL,
						"Failed to change directory.");
	} else {
		presponse_str = FTP_RESPONSE_STR(FTP_CWDOK,
				"Directory successfully changed.");
	}
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}
void do_cdup(session_t *sess)
{
	//CDUP返回上一级目录
	int ret = chdir("..");
	const char *presponse_str = NULL;
	if(ret < 0) {
		presponse_str = FTP_RESPONSE_STR(FTP_FILEFAIL,
						"Failed to change directory.");
	} else {
		presponse_str = FTP_RESPONSE_STR(FTP_CWDOK,
				"Directory successfully changed.");
	}
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}
void do_quit(session_t *sess)
{
	const char *presponse_str = \
		FTP_RESPONSE_STR(FTP_GOODBYE,"Goodbye.");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	exit(EXIT_SUCCESS);
}
void do_port(session_t *sess)
{
	////参数是客户端的IP和端口
	//FTP服务进程接收PORT h1,h2,h3,h4,p1,p2
	//解析ip port
	unsigned int v[6];
	sscanf(sess->arg,"%u,%u,%u,%u,%u,%u",
		&v[2],&v[3],&v[4],&v[5],&v[0],&v[1]);
	sess->port_addr = \
		(struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
	memset(sess->port_addr,0,sizeof(struct sockaddr_in));
	sess->port_addr->sin_family = AF_INET;
	uint8_t *p = (uint8_t *)(&sess->port_addr->sin_port);
	p[0] = v[0];
	p[1] = v[1];
	p = (uint8_t *)(&sess->port_addr->sin_addr.s_addr);
	p[0] = v[2];
	p[1] = v[3];
	p[2] = v[4];
	p[3] = v[5];
	//DEBUG_PRINT("client addr : %s\n",inet_ntoa(sess->port_addr->sin_addr));
	const char *presponse_str = FTP_RESPONSE_STR(FTP_PORTOK,
			"PORT command successful.Consider using PASV");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}
void do_pasv(session_t *sess)
{
	//被动方式的连接
	//227响应
	//发出监听命令
	priv_sock_send_cmd(sess->child_fd,PRIV_SOCK_PASV_LISTEN);
	//接收应答
	uint16_t port = (uint16_t)priv_sock_get_int(sess->child_fd);
	//将IP与端口格式化为h1,h2,h3,h4,p1,p2
	char ip[16] = {0};
	uint32_t v[4] = {0};
	//教程中的实现，对于系统是自动分配IP的情况不能使用
	//因为本身gethostbyname就是从/etc/hosts中获取ip
	//而这个数据要么在启动的时候配置写死，要么就是要
	//写脚本来进行配置。那么随着程序发布的就还有脚本配置
	//说明会造成使用上的不便，所以这里应该将问题解决在
	//内部，使用枚举网卡的方法来获取相关地址。
	getlocalip(ip);
	sscanf(ip,"%u.%u.%u.%u",&v[0],&v[1],&v[2],&v[3]);
	char text[1024] = {0};
	sprintf(text,"227 Entering Passive Mode (%u,%u,%u,%u,%u,%u).\r\n",
					v[0],v[1],v[2],v[3],port >> 8,port & 0xff);
	writen(sess->ctrl_fd,text,strlen(text));
}
void do_type(session_t *sess)
{
	const char *presponse_str = NULL;
	if(strcmp(sess->arg,"A") == 0) {
		presponse_str = FTP_RESPONSE_STR(FTP_TYPEOK,
						"Switching to ASCII mode.");
		sess->is_ascii = 1;
	} else if(strcmp(sess->arg,"I") == 0) {
		presponse_str = FTP_RESPONSE_STR(FTP_TYPEOK,
						"Switching to Binary mode.");
		sess->is_ascii = 0;
	} else {
		presponse_str = FTP_RESPONSE_STR(FTP_BADCMD,
						"Unrecognised TYPE command.");
		sess->is_ascii = 0;
	}
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}
void do_stru(session_t *sess)
{
}
void do_mode(session_t *sess)
{
}

void check_abor(session_t *sess)
{
	if(sess->abor_received) {
		sess->abor_received = 0;
		//226
		const char *presponse_str = \
			FTP_RESPONSE_STR(FTP_ABOROK,
					"ABOR successful.");
		writen(sess->ctrl_fd,presponse_str,
					strlen(presponse_str));
	}
}

void do_retr(session_t *sess)
{
	//下载文件
	//进行列表显示
	//创建数据连接
	//判断是主动还是被动连接
	if(0 == get_transfer_fd(sess)) {
		return;
	}
	const char *presponse_str;
	//打开文件
	int fd = open(sess->arg,O_RDONLY);
	if(fd < 0) {
		presponse_str = FTP_RESPONSE_STR(FTP_FILEFAIL,
							"Failed to open file.");
		writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
		return;
	}
	//加读锁防止其它进程进行改写
	int ret = lock_file_read(fd);
	if(ret < 0) {
		close(fd);
		//加锁失败，说明不能读，打开失败。
		presponse_str = FTP_RESPONSE_STR(FTP_FILEFAIL,
							"Failed to open file.");
		writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
		return;
	}
	//判断是否是普通文件
	struct stat sbuf;
	ret = fstat(fd,&sbuf);
	if(!S_ISREG(sbuf.st_mode)) {
		close(fd);
		presponse_str = FTP_RESPONSE_STR(FTP_FILEFAIL,
							"Failed to open file.");
		writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
		return;
	}
	//对位置进行定位
	off_t restart_pos_off = sess->restart_pos;
	sess->restart_pos = 0;
	if(0 != restart_pos_off) {
		ret = lseek(fd,restart_pos_off,SEEK_SET);
		if(ret < 0) {
			presponse_str = FTP_RESPONSE_STR(FTP_FILEFAIL,
								"Failed to open file.");
			writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
			return;
		}
	}
	//150
	//presponse_str = FTP_RESPONSE_STR(FTP_DATACONN,
	//				"Here comes the directory listing.");
	//writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	char text[1024] = {0};
	if(sess->is_ascii) {
		sprintf(text,"150 Opening ASCII mode data connection for %s (%ld bytes).\r\n",
															sess->arg,sbuf.st_size);
	} else {
		sprintf(text,"150 Opening BINARY mode data connection for %s (%ld bytes).\r\n",
															sess->arg,sbuf.st_size);
	}
	writen(sess->ctrl_fd,text,strlen(text));
	//传输数据
	int flag;
	if(sess->bw_download_rate_max != 0) {
		//如果限速就采取这种稍微低速一点的方法
		uint8_t buf[4096];
		sess->bw_transfer_start_sec = get_time_sec();
		sess->bw_transfer_start_usec = get_time_usec();
		while(1) {
			ret = readn(fd,buf,sizeof(buf));
			if(ret < 0) {
				if(EINTR == errno) {
					continue;
				} else {
					flag = 1;
					break;//读出现了错误
				}
			} else if(0 == ret) {
				flag = 0;
				break;//可能是文件读完成
			}
			limit_rate(sess,ret,0);
			if(sess->abor_received) {
				//要进行426的应答
				flag = 2;
				break;
			}
			if(ret != writen(sess->data_fd,buf,ret)) {
				flag = 2;
				break;//没有写入指定的数据
			}
		}
	} else {
		//为了提高效率可以直接使用sendfile函数进行文件传输。
		size_t bytes_to_send = sbuf.st_size;
		if(restart_pos_off > bytes_to_send) {
			bytes_to_send = 0;
		} else {
			bytes_to_send -= restart_pos_off;
		}
		while(bytes_to_send) {
			ret = sendfile(sess->data_fd,fd,NULL,bytes_to_send);
			if(ret < 0) {
				flag = 2;
				break;
			}
			bytes_to_send -= ret;
		}
		if(0 == bytes_to_send) {
			flag = 0;
		}
	}
	//关闭数据套接字
	//不关闭的话，客户端就无法判断是否已经接收完
	close(fd);
	close(sess->data_fd);
	sess->data_fd = -1;
	sess->data_process = 0;
	//226
	switch(flag)
	{
	case 0:
	{
		if(sess->abor_received) {
			presponse_str = FTP_RESPONSE_STR(FTP_ABOROK,
									"ABOR successful.");
			sess->abor_received = 0;
		} else {
			presponse_str = FTP_RESPONSE_STR(FTP_TRANSFEROK,
									"Transfer complete.");
		}
	}
		break;
	case 1:
		presponse_str = FTP_RESPONSE_STR(FTP_BADSENDFILE,
					"Failure reading from local file.");
		break;
	case 2:
		presponse_str = FTP_RESPONSE_STR(FTP_BADSENDNET,
					"Failure writting to network stream.");
		break;
	default:
		break;
	}
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	check_abor(sess);
}

void upload_common(session_t *sess,int isappe)
{
	//断点续传一个是REST方式，一个是APPE方式，大体相同
	if(0 == get_transfer_fd(sess)) {
		return;
	}
	const char *presponse_str;
	//打开文件
	int fd = open(sess->arg,O_CREAT | O_WRONLY,0666);
	if(fd < 0) {
		presponse_str = FTP_RESPONSE_STR(FTP_UPLOADFAIL,
							"Could not create file.");
		writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
		return;
	}
	//加写锁防止其它进程进行改写读
	int ret = lock_file_write(fd);
	if(ret < 0) {
		close(fd);
		//加锁失败，说明不能写，打开失败。
		presponse_str = FTP_RESPONSE_STR(FTP_UPLOADFAIL,
							"Could not create file.");
		writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
		return;
	}
	//对位置进行定位
	if(!isappe && 0 == sess->restart_pos) {
		//STOR
		ftruncate(fd,0);
		ret = lseek(fd,0,SEEK_SET);
	} else if(!isappe && 0 != sess->restart_pos) {
		//REST+STOR
		ret = lseek(fd,sess->restart_pos,SEEK_SET);
	} else if(isappe) {
		//追加就是偏移到文件末尾
		ret = lseek(fd,0,SEEK_END);
	}
	if(ret < 0) {
		presponse_str = FTP_RESPONSE_STR(FTP_UPLOADFAIL,
							"Could not create file.");
		writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
		return;
	}
	struct stat sbuf;
	ret = fstat(fd,&sbuf);
	off_t restart_pos_off = sess->restart_pos;
	sess->restart_pos = 0;
	//150
	//presponse_str = FTP_RESPONSE_STR(FTP_DATACONN,
	//				"Here comes the directory listing.");
	//writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	char text[1024] = {0};
	if(sess->is_ascii) {
		sprintf(text,"150 Opening ASCII mode data connection for %s (%ld bytes).\r\n",
															sess->arg,sbuf.st_size);
	} else {
		sprintf(text,"150 Opening BINARY mode data connection for %s (%ld bytes).\r\n",
															sess->arg,sbuf.st_size);
	}
	writen(sess->ctrl_fd,text,strlen(text));
	//传输数据
	int flag;
	uint8_t buf[4096];
	
	sess->bw_transfer_start_sec = get_time_sec();
	sess->bw_transfer_start_usec = get_time_usec();
	while(1) {
		ret = readn(sess->data_fd,buf,sizeof(buf));
		if(ret < 0) {
			if(EINTR == errno) {
				continue;
			} else {
				flag = 2;
				break;//读出现了错误
			}
		} else if(0 == ret) {
			flag = 0;
			break;//可能是文件读完成
		}
		//写之前判断下是否需要进行限速
		limit_rate(sess,ret,1);
		if(sess->abor_received) {
			flag = 2;
			break;
		}
		if(ret != writen(fd,buf,ret)) {
			flag = 1;
			break;//没有写入指定的数据
		}
	}
	//关闭数据套接字
	//不关闭的话，客户端就无法判断是否已经接收完
	close(fd);
	close(sess->data_fd);
	sess->data_fd = -1;
	sess->data_process = 0;
	//226
	switch(flag)
	{
	case 0:
	{
		if(sess->abor_received) {
			presponse_str = FTP_RESPONSE_STR(FTP_ABOROK,
									"ABOR successful.");
			sess->abor_received = 0;
		} else {
			presponse_str = FTP_RESPONSE_STR(FTP_TRANSFEROK,
									"Transfer complete.");
		}
	}
		break;
	case 1:
		presponse_str = FTP_RESPONSE_STR(FTP_BADSENDFILE,
					"Failure writting to local file.");
		break;
	case 2:
		presponse_str = FTP_RESPONSE_STR(FTP_BADSENDNET,
					"Failure reading from network stream.");
		break;
	default:
		break;
	}
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	check_abor(sess);
}

void do_stor(session_t *sess)
{
	upload_common(sess,0);
}
void do_appe(session_t *sess)
{
	//appe所携带的参数是文件名字
	upload_common(sess,1);
}
void do_list(session_t *sess)
{
	//进行列表显示
	//创建数据连接
	//判断是主动还是被动连接
	if(0 == get_transfer_fd(sess)) {
		return;
	}
	//150
	const char *presponse_str = FTP_RESPONSE_STR(FTP_DATACONN,
						"Here comes the directory listing.");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	//传输列表
	list_command(sess,1);
	//关闭数据套接字
	//不关闭的话，客户端就无法判断是否已经接收完
	close(sess->data_fd);
	sess->data_fd = -1;
	//226
	presponse_str = FTP_RESPONSE_STR(FTP_TRANSFEROK,
							"Directory send OK.");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}
void do_nlst(session_t *sess)
{
	//只返回短的只包含文件名字的清单
	//进行列表显示
	//创建数据连接
	//判断是主动还是被动连接
	if(0 == get_transfer_fd(sess)) {
		return;
	}
	//150
	const char *presponse_str = FTP_RESPONSE_STR(FTP_DATACONN,
						"Here comes the directory listing.");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	//传输列表
	list_command(sess,0);
	//关闭数据套接字
	//不关闭的话，客户端就无法判断是否已经接收完
	close(sess->data_fd);
	sess->data_fd = -1;
	//226
	presponse_str = FTP_RESPONSE_STR(FTP_TRANSFEROK,
							"Directory send OK.");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}
void do_rest(session_t *sess)
{
	//REST重置，和断点续传有关
	sess->restart_pos = atoll(sess->arg);
	char buf[1024] = {0};
	sprintf(buf,"350 Restart position accepted (%lld).\r\n",
										sess->restart_pos);
	writen(sess->ctrl_fd,buf,strlen(buf));
}
void do_abor(session_t *sess)
{
	//直接收到ABOR，需要响应225
	const char *presponse_str = \
		FTP_RESPONSE_STR(FTP_ABOR_NOCONN,
				"No transfer to ABOR.");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}
void do_pwd(session_t *sess)
{
	//将当前用户家目录进行响应
	char dir[PATH_MAX] = {0};
	char dirbuf[PATH_MAX + 100] = {0};
	getcwd(dir,PATH_MAX);
	sprintf(dirbuf,"%s \"%s\"\r\n",FTP_PWDOK,dir);
	////DEBUG_PRINT("%s\n",dirbuf);
	writen(sess->ctrl_fd,dirbuf,strlen(dirbuf));
}
void do_mkd(session_t *sess)
{
	////DEBUG_PRINT("%s sess->arg:%s\n",__func__,sess->arg);
	int ret;
	char real_dir[2048] = {0};
	memset(real_dir,0,sizeof(real_dir));
	if(sess->arg[0] == '/') {
		////DEBUG_PRINT("sess->arg:%s\n",sess->arg);
		ret = mkdir(sess->arg,0777);
	} else {
		char dir[1024] = {0};
		getcwd(dir,sizeof(dir));
		if(dir[strlen(dir) - 1] == '/') {
			sprintf(real_dir,"%s%s",dir,sess->arg);
		} else {
			sprintf(real_dir,"%s/%s",dir,sess->arg);
		}
		////DEBUG_PRINT("real_dir:%s\n",real_dir);
		ret = mkdir(real_dir,0777);
	}
	if(ret < 0) {
		perror("mkdir");
		const char *presponse_str = FTP_RESPONSE_STR(FTP_FILEFAIL,
							"Create directory operation failed.");
		writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	} else {
		char resp_buf[4096];
		memset(resp_buf,0,sizeof(resp_buf));
		//首先判断是否是绝对路径
		if(sess->arg[0] == '/') {
			sprintf(resp_buf,"257 \"%s\" created\r\n",sess->arg);
		} else {
			sprintf(resp_buf,"257 \"%s\" created\r\n",real_dir);
		}
		writen(sess->ctrl_fd,resp_buf,strlen(resp_buf));
	}
}
void do_rmd(session_t *sess)
{
	int ret = rmdir(sess->arg);
	const char *presponse_str;
	if(ret < 0) {
		perror("rmdir");
		presponse_str = FTP_RESPONSE_STR(FTP_FILEFAIL,
					"Remove directory operation failed.");
	} else {
		presponse_str = FTP_RESPONSE_STR(FTP_RMDIROK,
				"Remove directory operation successful.");
	}
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}
void do_dele(session_t *sess)
{
	int ret = unlink(sess->arg);
	const char *presponse_str;
	if(ret < 0) {
		perror("unlink");
		presponse_str = FTP_RESPONSE_STR(FTP_FILEFAIL,
						"Delete operation failed.");
	} else {
		presponse_str = FTP_RESPONSE_STR(FTP_DELEOK,
							"Delete operation successful.");
	}
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}
void do_rnfr(session_t *sess)
{
	//重命名前的文件
	int name_len = strlen(sess->arg) + 1;
	if(NULL != sess->rnfr_name) {
		free(sess->rnfr_name);
	}
	sess->rnfr_name = (char *)malloc(name_len);
	memset(sess->rnfr_name,0,name_len);
	strcpy(sess->rnfr_name,sess->arg);
	const char *presponse_str = FTP_RESPONSE_STR(FTP_RNFROK,
										"Ready for RNTO.");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}
void do_rnto(session_t *sess)
{
	//重命名后的文件
	const char *presponse_str;
	if(NULL == sess->rnfr_name) {
		presponse_str = FTP_RESPONSE_STR(FTP_NEEDRNFR,
								"RNFR required first.");
	} else {
		int ret = rename(sess->rnfr_name,sess->arg);
		if(ret < 0) {
			presponse_str = FTP_RESPONSE_STR(FTP_FILEFAIL,
								"Rename operation failed.");
		} else {
			presponse_str = FTP_RESPONSE_STR(FTP_RENAMEOK,
									"Rename successful.");
		}
		free(sess->rnfr_name);
		sess->rnfr_name = NULL;
	}
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}

void do_site_chmod(int fd,char *arg)
{
	const char *presponse_str;
	DEBUG_PRINT("arg:%s\n",arg);
	if(strlen(arg) == 0) {
		presponse_str = \
			FTP_RESPONSE_STR(FTP_BADCMD,
				"SITE CHMOD needs 2 arguments.");
		writen(fd,presponse_str,strlen(presponse_str));
		return;
	}
	if(arg[0] == ' ') {
		arg[0] = '0';
	}
	char perm[100] = {0};
	char file[100] = {0};
	str_split(arg,perm,file,' ');
	if(strlen(file) == 0) {
		presponse_str = \
			FTP_RESPONSE_STR(FTP_BADCMD,
				"SITE CHMOD needs 2 arguments.");
		writen(fd,presponse_str,strlen(presponse_str));
		return;
	}
	DEBUG_PRINT("perm:%s,file:%s\n",perm,file);
	int mode = atoi_sint32_ex(perm);
	if(chmod(file,mode) < 0) {
		presponse_str = \
			FTP_RESPONSE_STR(FTP_CHMODOK,
				"SITE CHMOD command failed.");
		writen(fd,presponse_str,strlen(presponse_str));
	} else {
		presponse_str = \
			FTP_RESPONSE_STR(FTP_CHMODOK,
				"SITE CHMOD command ok.");
		writen(fd,presponse_str,strlen(presponse_str));
	}
}

void do_site_umask(int fd,char *arg)
{
	char buf[1024] = {0};
	DEBUG_PRINT("arg:%s\n",arg);
	if(strlen(arg) == 0) {
		sprintf(buf,"200 Your current UMASK is 0%o\r\n",
									tunable_local_umask);
		writen(fd,buf,strlen(buf));
		return;
	} else {
		int len = strlen(arg);
		int i = 0;
		for(i = 0;i < len;++i) {
			arg[i] = arg[i + 1];
		}
		tunable_local_umask = atoi_sint32_ex(arg);
		umask(tunable_local_umask);
		sprintf(buf,"200 UMASK set to 0%o\r\n",
							tunable_local_umask);
		writen(fd,buf,strlen(buf));
	}
}

void do_site(session_t *sess)
{
	char cmd[100] = {0};
	char arg[100] = {0};
	str_split(sess->cmdline + strlen(sess->cmd) \
								+ 1,cmd,arg,' ');
	DEBUG_PRINT("do_site cmdline:%s\n",sess->cmdline);
	const char * presponse_str;
	if(strcmp(sess->arg,"CHMOD") == 0) {
		do_site_chmod(sess->ctrl_fd,sess->cmdline + \
			strlen(sess->cmd) + strlen(sess->arg) + 1);
	} else if(strcmp(sess->arg,"UMASK") == 0) {
		do_site_umask(sess->ctrl_fd,sess->cmdline + \
			strlen(sess->cmd) + strlen(sess->arg) + 1);
	} else if(strcmp(sess->arg,"HELP") == 0) {
		presponse_str = \
			FTP_RESPONSE_STR(FTP_SITEHELP,"CHMOD UMASK HELP");
		writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	} else {
		presponse_str = \
			FTP_RESPONSE_STR(FTP_BADCMD,"Unknown SITE command.");
		writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	}
}
void do_syst(session_t *sess)
{
	//登陆后会执行这个命令，要响应215
	const char *presponse_str = \
		FTP_RESPONSE_STR(FTP_SYSTOK,"UNIX Type:L8");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}
void do_feat(session_t *sess)
{
	//返回服务端的特性
	//REST和断点续传有关
	//这里要将特性描述上
	const char *presponse_str = FTP_LRESPONSE_STR(FTP_FEAT,"Features:");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	presponse_str = " EPRT\r\n";
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	presponse_str = " EPSV\r\n";
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	presponse_str = " MDTM\r\n";
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	presponse_str = " PASV\r\n";
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	presponse_str = " REST STREAM\r\n";
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	presponse_str = " SIZE\r\n";
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	presponse_str = " TVFS\r\n";
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	presponse_str = " UTF8\r\n";
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	presponse_str = FTP_RESPONSE_STR(FTP_FEAT,"End");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}
void do_size(session_t *sess)
{
	//查看文件的大小，给客户端一个213的响应
	struct stat sbuf;
	int ret = lstat(sess->arg,&sbuf);
	const char *presponse_str = NULL;
	if(ret < 0) {
		presponse_str = FTP_RESPONSE_STR(FTP_FILEFAIL,
							"SIZE operation failed.");
		writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	}
	//如果不是普通文件
	if(!S_ISREG(sbuf.st_mode)) {
		presponse_str = FTP_RESPONSE_STR(FTP_FILEFAIL,
						"Could not get file size.");
		writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	}
	char resp_buf[1024] = {0};
	sprintf(resp_buf,"213 %ld",sbuf.st_size);
	writen(sess->ctrl_fd,resp_buf,strlen(resp_buf));
}
void do_stat(session_t *sess)
{
	const char *presponse_str = \
		FTP_LRESPONSE_STR(FTP_STATOK,"FTP server status:");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	char buf[1024] = {0};
	if(0 == sess->bw_upload_rate_max) {
		sprintf(buf,"\tNo Session upload bandwidth limit\r\n");
	} else if(sess->bw_upload_rate_max > 0) {
		sprintf(buf,"\tSession upload bandwidth limit in byte/s is %u\r\n",
												sess->bw_upload_rate_max);
	}
	writen(sess->ctrl_fd,buf,strlen(buf));
	memset(buf,0,sizeof(buf));
	if(0 == sess->bw_download_rate_max) {
		sprintf(buf,"\tNo Session download bandwidth limit\r\n");
	} else if(sess->bw_download_rate_max > 0) {
		sprintf(buf,"\tSession download bandwidth limit in byte/s is %u\r\n",
												sess->bw_download_rate_max);
	}
	writen(sess->ctrl_fd,buf,strlen(buf));
	memset(buf,0,sizeof(buf));
	sprintf(buf,"\tAt session startup,client count was %u\r\n",
											sess->num_clients);
	writen(sess->ctrl_fd,buf,strlen(buf));
	presponse_str = FTP_RESPONSE_STR(FTP_STATOK,"End of status");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}
void do_noop(session_t *sess)
{
	const char *presponse_str = \
		FTP_RESPONSE_STR(FTP_NOOPOK,"NOOP ok.");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}
void do_help(session_t *sess)
{
	const char *presponse_str = \
		FTP_RESPONSE_STR(FTP_HELP,"The following commands are recognized.");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	presponse_str = " ABOR ACCT ALLO APPE CDUP CWD  DELE EPRT EPSV FEAT HELP LIST MDTM MKD\r\n";
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	presponse_str = " MODE NLST NOOP OPTS PASS PASV PORT PWD  QUIT REIN REST RETR RMD  RNFR\r\n";
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	presponse_str = " RNTO SITE SIZE SMNT STAT STOR STOU STRU SYST TYPE USER XCUP XCWD XMKD\r\n";
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	presponse_str = " XPWD XRMD\r\n";
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
	presponse_str = FTP_RESPONSE_STR(FTP_HELP,"Help OK.");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}

void do_opts(session_t *sess)
{
	const char *presponse_str = FTP_RESPONSE_STR(FTP_OPTSOK,"Always in UTF8 mode.");
	writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
}

void do_mdtm(session_t *sess)
{
	struct timeval tv;
	gettimeofday(&tv,NULL);
	time_t local_time = tv.tv_sec;
	char datebuf[1024] = {0};
	char timebuf[1024] = {0};
	memset(datebuf,0,sizeof(datebuf));
	memset(timebuf,0,sizeof(timebuf));
	struct tm* p_tm = localtime(&local_time);
	strftime(timebuf,sizeof(timebuf),"%Y%m%d%H%M%S",p_tm);
	sprintf(datebuf,"213 %s\r\n",timebuf);
	writen(sess->ctrl_fd,datebuf,sizeof(datebuf));
}

int
list_command(session_t *sess,int detail)
{
	DIR *dir = opendir(".");
	if(NULL == dir) {
		return 0;
	}
	struct dirent *dt;
	struct stat sbuf;
	char buf[1024] = {0};
	char datebuf[64] = {0};
	char tmp[1024] = {0};
	__off_t off = 0;
	while(NULL != (dt = readdir(dir))) {
		if(dt->d_name[0] == '.') {
			continue;
		}
		if(lstat(dt->d_name,&sbuf) < 0) {
			continue;
		}
		memset(buf,0,sizeof(buf));
		off = 0;
		if(detail) {
			//将这些信息打印出来
			char perms[11] = {[0 ... 9] = '-',0};
			perms[0] = '?';
			mode_t mode = sbuf.st_mode;
			//获取文件类型
			switch(mode & S_IFMT)
			{
			case S_IFREG:
				perms[0] = '-';
				break;
			case S_IFDIR:
				perms[0] = 'd';
				break;
			case S_IFLNK:
				perms[0] = 'l';
				break;
			case S_IFIFO:
				perms[0] = 'p';
				break;
			case S_IFSOCK:
				perms[0] = 's';
				break;
			case S_IFCHR:
				perms[0] = 'c';
				break;
			case S_IFBLK:
				perms[0] = 'b';
				break;
			default:
				break;
			}
			//获取权限位
			if(mode & S_IRUSR) {
				perms[1] = 'r';
			}
			if(mode & S_IWUSR) {
				perms[2] = 'w';
			}
			if(mode &S_IXUSR) {
				perms[3] = 'x';
			}

			if(mode & S_IRGRP) {
				perms[4] = 'r';
			}
			if(mode & S_IWGRP) {
				perms[5] = 'w';
			}
			if(mode &S_IXGRP) {
				perms[6] = 'x';
			}

			if(mode & S_IROTH) {
				perms[7] = 'r';
			}
			if(mode & S_IWOTH) {
				perms[8] = 'w';
			}
			if(mode &S_IXOTH) {
				perms[9] = 'x';
			}

			if(mode & S_ISUID) {
				perms[3] = ('x' == perms[3]) ? 's' : 'S';
			}
			if(mode & S_ISGID) {
				perms[6] = ('x' == perms[6]) ? 's' : 'S';
			}
			if(mode & S_ISVTX) {
				perms[9] = ('x' == perms[6]) ? 's' : 'S';
			}
			//连接数 硬连接数 uid gid 尺寸 
			off += sprintf(buf,"%s ",perms);
			off += sprintf(buf + off,"%3ld %-8d %-8d ",
				sbuf.st_nlink,sbuf.st_uid,sbuf.st_gid);
			off += sprintf(buf + off,"%8lu ",sbuf.st_size);
			const char *p_data_format;
			struct timeval tv;
			gettimeofday(&tv,NULL);
			time_t local_time = tv.tv_sec;
			if(sbuf.st_mtime > local_time || \
				(local_time - sbuf.st_mtime) > 182 * 24 * 60 * 60) {
				p_data_format = "%b %e %Y";
			} else {
				p_data_format = "%b %e %H:%M";
			}
			memset(datebuf,0,sizeof(datebuf));
			struct tm* p_tm = localtime(&local_time);
			strftime(datebuf,sizeof(datebuf),p_data_format,p_tm);
			off += sprintf(buf + off,"%s ",datebuf);
			//还需要处理符号连接的显示情况
			if(S_ISLNK(sbuf.st_mode)) {
				memset(tmp,0,sizeof(tmp));
				readlink(dt->d_name,tmp,sizeof(tmp));
				off += sprintf(buf + off,"%s -> ",tmp);
			}
		}
		sprintf(buf + off,"%s\r\n",dt->d_name);
		//DEBUG_PRINT("%s\n",buf);
		writen(sess->data_fd,buf,strlen(buf));
	}
	closedir(dir);
	return 1;
}

int port_active(session_t *sess);
int pasv_active(session_t *sess);

int
port_active(session_t *sess)
{
	if(NULL != sess->port_addr) {
		//如果被动模式也处于被激活的状态那么这里有问题
		if(pasv_active(sess)) {
			fprintf(stderr,
				"when port mode is avilable the pasv mode must be unavilable.\n");
			return 0;
		}
		return 1;
	}
	return 0;
}

int
pasv_active(session_t *sess)
{
	priv_sock_send_cmd(sess->child_fd,PRIV_SOCK_PASV_ACTIVE);
	int active = priv_sock_get_int(sess->child_fd);
	if(active) {
		if(port_active(sess)) {
			fprintf(stderr,
				"when pasv mode is avilable the port mode must be unavilable.\n");
			return 0;
		}
		return 1;
	}
	return 0;
}

int
get_port_fd(session_t *sess)
{
	priv_sock_send_cmd(sess->child_fd,PRIV_SOCK_GET_DATA_SOCK);
	uint16_t port = ntohs(sess->port_addr->sin_port);
	char *ip = inet_ntoa(sess->port_addr->sin_addr);
	priv_sock_send_int(sess->child_fd,port);
	priv_sock_send_buf(sess->child_fd,ip,strlen(ip));

	int res = priv_sock_get_result(sess->child_fd);
	if(PRIV_SOCK_RESULT_BAD == res) {
		return 0;
	} else if(PRIV_SOCK_RESULT_OK == res) {
		//接收文件描述符
		sess->data_fd = priv_sock_recv_fd(sess->child_fd);
	}
	return 1;
}

int
get_pasv_fd(session_t *sess)
{
	priv_sock_send_cmd(sess->child_fd,PRIV_SOCK_PASV_ACCEPT);
	char res = priv_sock_get_result(sess->child_fd);
	if(PRIV_SOCK_RESULT_BAD == res) {
		return 0;
	} else if(PRIV_SOCK_RESULT_OK) {
		sess->data_fd = priv_sock_recv_fd(sess->child_fd);
	}
	return 1;
}

int
get_transfer_fd(session_t *sess)
{
	//判断是主动还是被动连接
	if(!port_active(sess) && !pasv_active(sess)) {
		//这里要响应错误，以免客户端进入阻塞状态
		const char *presponse_str = FTP_RESPONSE_STR(FTP_BADSENDCONN,
										"USE PORT or PASV first.");
		writen(sess->ctrl_fd,presponse_str,strlen(presponse_str));
		return 0;
	}
	int ret = 1;
	if(port_active(sess)) {
		//绑定20端口主动发起连接
		//这里应向nobody进程发送使用20端口向客户端发出连接的请求
		//向nobody发送PRIV_SOCK_GET_DATA_SOCK命令
		//向nobody发送端口号（整数）和ip（字符串）
		ret = get_port_fd(sess);
	} else if(pasv_active(sess)) {
		ret = get_pasv_fd(sess);
	}
	if(NULL != sess->port_addr) {
		free(sess->port_addr);
		sess->port_addr = NULL;
	}
	if(ret) {
		//重新安装闹钟并启动
		start_data_alarm();
	}
	return ret;
}

void limit_rate(session_t *sess,int bytes_transfered,int is_upload)
{
	sess->data_process = 1;
	//睡眠时间=（当前传输速度/最大传输速度-1）*当前传输时间
	long curr_sec = get_time_sec();
	long curr_usec = get_time_usec();

	double elapsed = curr_sec - sess->bw_transfer_start_sec;
	elapsed += (double)(curr_usec - sess->bw_transfer_start_usec) / 1000000.0F;
	if(elapsed <= 0) {
		elapsed = 0.01;
	}
	//计算当前传输速度
	uint32_t bw_rate = (uint32_t)((double)bytes_transfered / elapsed);
	//和限制的速度进行比例计算得到要睡眠的时间
	double rate_ration;
	if(is_upload) {
		if(bw_rate <= sess->bw_upload_rate_max) {
			//不需要限速
			sess->bw_transfer_start_sec = get_time_sec();
			sess->bw_transfer_start_usec = get_time_usec();
			return;
		}
		//注意这里算的是比例
		rate_ration = bw_rate / sess->bw_upload_rate_max;
	} else {
		if(bw_rate <= sess->bw_download_rate_max) {
			sess->bw_transfer_start_sec = get_time_sec();
			sess->bw_transfer_start_usec = get_time_usec();
			return;
		}
		rate_ration = bw_rate / sess->bw_download_rate_max;
	}
	//套公式计算睡眠时间
	double pause_time;
	pause_time = (rate_ration - 1.0f) * elapsed;
	nano_sleep(pause_time);
	//继续获取当前时间
	sess->bw_transfer_start_sec = get_time_sec();
	sess->bw_transfer_start_usec = get_time_usec();
}
